﻿using System;
using ch11.binary;
using ch11.instance;

namespace ch11.cmd
{
    using WasmVal = Object;

    public static class Native
    {
        public static IModule newEnv()
        {
            var env = NativeModule.NewNativeInstance();
            env.RegisterFunc("print_char(i32)->()", PrintChar);
            env.RegisterFunc("assert_true(i32)->()", AssertTrue);
            env.RegisterFunc("assert_false(i32)->()", AssertFalse);
            env.RegisterFunc("assert_eq_i32(i32,i32)->()", AssertEqI32);
            env.RegisterFunc("assert_eq_i64(i64,i64)->()", AssertEqI64);
            env.RegisterFunc("assert_eq_f32(f32,f32)->()", AssertEqF32);
            env.RegisterFunc("assert_eq_f64(f64,f64)->()", AssertEqF64);
            return env;
        }

        public static (WasmVal[], Exception) PrintChar(WasmVal[] args)
        {
            Console.Write(Convert.ToChar(args[0]));
            return (null, null);
        }

        public static (WasmVal[], Exception) AssertTrue(WasmVal[] args)
        {
            AssertEq((int) args[0], 1);
            return (null, null);
        }

        public static (WasmVal[], Exception) AssertFalse(WasmVal[] args)
        {
            AssertEq((int) args[0], 0);
            return (null, null);
        }

        public static (WasmVal[], Exception) AssertEqI32(WasmVal[] args)
        {
            AssertEq((int) args[0], (int) args[1]);
            return (null, null);
        }

        public static (WasmVal[], Exception) AssertEqI64(WasmVal[] args)
        {
            AssertEq((long) args[0], (long) args[1]);
            return (null, null);
        }

        public static (WasmVal[], Exception) AssertEqF32(WasmVal[] args)
        {
            AssertEq((float) args[0], (float) args[1]);
            return (null, null);
        }

        public static (WasmVal[], Exception) AssertEqF64(WasmVal[] args)
        {
            AssertEq((double) args[0], (double) args[1]);
            return (null, null);
        }

        private static void AssertEq(WasmVal a, WasmVal b)
        {
            if (!a.Equals(b))
            {
                Panic.Run($"{a:G} != {b:G}");
            }
        }
    }
}